Saznajte kako nadzirati promjene lokalnih datoteka i direktorija izravno iz preglednika pomoću File System Access API-ja. Naš vodič nudi primjere i savjete za performanse.
Otključavanje snage frontenda u stvarnom vremenu: Detaljan pregled nadzora direktorija datotečnog sustava
Zamislite web-uređivač koda koji trenutačno odražava promjene koje napravite u mapi projekta na vašem lokalnom disku. Zamislite galeriju fotografija u pregledniku koja se automatski ažurira kada dodate nove slike s fotoaparata. Ili razmislite o alatu za vizualizaciju podataka koji iscrtava svoje grafikone u stvarnom vremenu kako se ažurira lokalna datoteka zapisnika. Desetljećima je ova razina integracije s lokalnim datotečnim sustavom bila isključiva domena izvornih (native) desktop aplikacija. Preglednik je, iz sigurnosnih razloga, držan na sigurnoj udaljenosti u svom izoliranom okruženju (sandboxu).
Danas se ta paradigma dramatično mijenja. Zahvaljujući modernim API-jima preglednika, granica između web i desktop aplikacija se briše. Jedan od najmoćnijih alata koji predvodi ovu promjenu je File System Access API, koji web aplikacijama daje pristup temeljen na dopuštenjima za čitanje, pisanje i, što je najvažnije za našu raspravu, nadzor promjena u korisničkim lokalnim datotekama i direktorijima. Ova sposobnost, poznata kao nadzor direktorija ili praćenje promjena datoteka, otvara novu granicu za stvaranje moćnih, responzivnih i visoko integriranih web iskustava.
Ovaj sveobuhvatni vodič provest će vas kroz detaljan pregled svijeta nadzora direktorija datotečnog sustava na frontendu. Istražit ćemo temeljni API, analizirati tehnike za izgradnju robusnog nadzornika od nule, ispitati stvarne slučajeve upotrebe i proći kroz ključne izazove performansi, sigurnosti i korisničkog iskustva. Bilo da gradite sljedeći veliki web-IDE ili jednostavan uslužni alat, razumijevanje ove tehnologije ključno je za otključavanje punog potencijala modernog weba.
Evolucija: od jednostavnih unosa datoteka do nadzora u stvarnom vremenu
Da bismo u potpunosti cijenili značaj File System Access API-ja, korisno je pogledati unatrag na put rukovanja datotekama na webu.
Klasični pristup: <input type="file">
Dugo vremena, naš jedini ulaz u korisnikov datotečni sustav bio je skromni element <input type="file">. Bio je, i još uvijek jest, pouzdan radni konj za jednostavno učitavanje datoteka. Međutim, njegova su ograničenja značajna:
- Pokrenuto od strane korisnika i jednokratno: Korisnik mora ručno kliknuti gumb i odabrati datoteku svaki put. Ne postoji postojanost.
- Samo datoteke: Mogli ste odabrati jednu ili više datoteka, ali nikada niste mogli odabrati cijeli direktorij.
- Bez nadzora: Jednom kada je datoteka odabrana, preglednik nije imao saznanja o tome što se dogodilo s izvornom datotekom na disku. Ako je izmijenjena ili izbrisana, web aplikacija je ostala nesvjesna.
Korak naprijed: Drag and Drop API
Drag and Drop API pružio je znatno poboljšano korisničko iskustvo, omogućujući korisnicima da povuku datoteke i mape izravno na web stranicu. To se činilo intuitivnijim i sličnijim desktopu. Ipak, dijelio je temeljno ograničenje s unosom datoteka: bio je to jednokratan događaj. Aplikacija je primila snimku povučenih stavki u tom određenom trenutku i nije imala trajnu vezu s izvornim direktorijem.
Prekretnica: The File System Access API
File System Access API predstavlja temeljni iskorak. Dizajniran je da web aplikacijama pruži mogućnosti koje konkuriraju izvornim aplikacijama, omogućujući im interakciju s korisnikovim lokalnim datotečnim sustavom na postojan i moćan način. Njegova temeljna načela izgrađena su oko sigurnosti, pristanka korisnika i sposobnosti:
- Sigurnost usmjerena na korisnika: Pristup se nikada ne dodjeljuje tiho. Korisnik se uvijek pita za dopuštenje za pristup određenoj datoteci ili direktoriju putem izvornog dijaloškog okvira preglednika.
- Postojane reference (handles): Umjesto da primi jednokratni blob podataka, vaša aplikacija dobiva poseban objekt nazvan referenca (FileSystemFileHandle ili FileSystemDirectoryHandle). Ova referenca djeluje kao postojani pokazivač na stvarnu datoteku ili direktorij na disku.
- Pristup na razini direktorija: Ovo je ključna značajka. API omogućuje korisniku da aplikaciji odobri pristup cijelom direktoriju, uključujući sve njegove poddirektorije i datoteke.
Upravo ova postojana referenca direktorija omogućuje praćenje datoteka u stvarnom vremenu na frontendu.
Razumijevanje File System Access API-ja: temeljna tehnologija
Prije nego što možemo izgraditi nadzornik direktorija, moramo razumjeti ključne komponente API-ja koje ga omogućuju. Cijeli API je asinkron, što znači da svaka operacija koja komunicira s datotečnim sustavom vraća Promise, osiguravajući da korisničko sučelje ostane responzivno.
Sigurnost i dopuštenja: korisnik ima kontrolu
Najvažniji aspekt ovog API-ja je njegov sigurnosni model. Web stranica ne može proizvoljno skenirati vaš tvrdi disk. Pristup je strogo temeljen na pristanku.
- Početni pristup: Korisnik mora pokrenuti radnju, poput klika na gumb, koja poziva metodu API-ja kao što je window.showDirectoryPicker(). Time se otvara poznati dijaloški okvir na razini OS-a gdje korisnik odabire direktorij i izričito klika na "Odobri pristup" ili sličan gumb.
- Stanja dopuštenja: Dopuštenje stranice za danu referencu može biti u jednom od tri stanja: 'prompt' (zadano, zahtijeva pitanje korisnika), 'granted' (stranica ima pristup) ili 'denied' (stranica ne može pristupiti i ne može ponovno pitati u istoj sesiji).
- Postojanost: Za bolje korisničko iskustvo, preglednik može zadržati 'granted' dopuštenje između sesija za instalirane PWA ili stranice s visokim angažmanom. To znači da korisnik možda neće morati ponovno birati mapu projekta svaki put kad posjeti vašu aplikaciju. Trenutno stanje dopuštenja možete provjeriti s directoryHandle.queryPermission() i zatražiti njegovo odobrenje s directoryHandle.requestPermission().
Ključne metode za dobivanje pristupa
Ulazne točke u API su tri globalne metode na objektu window:
- window.showOpenFilePicker(): Traži od korisnika da odabere jednu ili više datoteka. Vraća niz FileSystemFileHandle objekata.
- window.showDirectoryPicker(): Ovo je naš primarni alat. Traži od korisnika da odabere direktorij. Vraća jedan FileSystemDirectoryHandle.
- window.showSaveFilePicker(): Traži od korisnika da odabere lokaciju za spremanje datoteke. Vraća FileSystemFileHandle za pisanje.
Snaga referenci: FileSystemDirectoryHandle
Jednom kada imate FileSystemDirectoryHandle, imate moćan objekt koji predstavlja taj direktorij. On не sadrži sadržaj direktorija, ali vam daje metode za interakciju s njim:
- Iteracija: Možete iterirati preko sadržaja direktorija koristeći asinkroni iterator: for await (const entry of directoryHandle.values()) { ... }. Svaki entry bit će ili FileSystemFileHandle ili drugi FileSystemDirectoryHandle.
- Dohvaćanje specifičnih unosa: Možete dobiti referencu za određenu poznatu datoteku ili poddirektorij koristeći directoryHandle.getFileHandle('filename.txt') ili directoryHandle.getDirectoryHandle('subfolder').
- Izmjena: Možete stvoriti nove datoteke i poddirektorije dodavanjem opcije { create: true } gornjim metodama, ili ih ukloniti s directoryHandle.removeEntry('item-to-delete').
Srž stvari: Implementacija nadzora direktorija
Ovdje je ključan detalj: File System Access API ne pruža izvorni, događajima vođen mehanizam za nadzor poput Node.js-ovog fs.watch(). Ne postoji metoda directoryHandle.on('change', ...). Ovo je često tražena značajka, ali za sada moramo sami implementirati logiku nadzora.
Najčešći i najpraktičniji pristup je periodično prozivanje (polling). To uključuje stvaranje "snimke stanja" direktorija u redovitim intervalima i uspoređivanje s prethodnom snimkom kako bi se otkrile promjene.
Naivni pristup: Jednostavna petlja prozivanja
Osnovna implementacija mogla bi izgledati otprilike ovako:
// Pojednostavljeni primjer za ilustraciju koncepta
let initialFiles = new Set();
async function watchDirectory(directoryHandle) {
const currentFiles = new Set();
for await (const entry of directoryHandle.values()) {
currentFiles.add(entry.name);
}
// Usporedba s prethodnim stanjem (ova je logika previše pojednostavljena)
console.log("Direktorij provjeren. Trenutne datoteke:", Array.from(currentFiles));
// Ažuriranje stanja za sljedeću provjeru
initialFiles = currentFiles;
}
// Pokreni nadzor
async function start() {
const directoryHandle = await window.showDirectoryPicker();
setInterval(() => watchDirectory(directoryHandle), 2000); // Provjera svake 2 sekunde
}
Ovo funkcionira, ali je vrlo ograničeno. Provjerava samo direktorij najviše razine, može otkriti samo dodavanja/brisanja (ne i izmjene) i nije enkapsulirano. To je polazišna točka, ali možemo puno bolje.
Sofisticiraniji pristup: Izgradnja rekurzivne klase za nadzor
Da bismo stvorili zaista koristan nadzornik direktorija, trebamo robusnije rješenje. Dizajnirajmo klasu koja rekurzivno skenira direktorij, prati metapodatke datoteka kako bi otkrila izmjene i emitira jasne događaje za različite vrste promjena.
Korak 1: Stvaranje detaljne snimke stanja
Prvo, trebamo funkciju koja može rekurzivno proći kroz direktorij i izgraditi detaljnu mapu njegovog sadržaja. Ova mapa trebala bi uključivati ne samo nazive datoteka već i metapodatke, poput vremenske oznake lastModified, koja je ključna za otkrivanje promjena.
// Funkcija za rekurzivno stvaranje snimke stanja direktorija
async function createSnapshot(dirHandle, path = '') {
const snapshot = new Map();
for await (const entry of dirHandle.values()) {
const currentPath = path ? `${path}/${entry.name}` : entry.name;
if (entry.kind === 'file') {
const file = await entry.getFile();
snapshot.set(currentPath, {
lastModified: file.lastModified,
size: file.size,
handle: entry
});
} else if (entry.kind === 'directory') {
const subSnapshot = await createSnapshot(entry, currentPath);
subSnapshot.forEach((value, key) => snapshot.set(key, value));
}
}
return snapshot;
}
Korak 2: Usporedba snimki stanja za pronalaženje promjena
Zatim, trebamo funkciju koja uspoređuje staru snimku s novom i identificira točno što se promijenilo.
// Funkcija za usporedbu dviju snimki stanja i vraćanje promjena
function compareSnapshots(oldSnapshot, newSnapshot) {
const changes = {
added: [],
modified: [],
deleted: []
};
// Provjera dodanih i izmijenjenih datoteka
newSnapshot.forEach((newFile, path) => {
const oldFile = oldSnapshot.get(path);
if (!oldFile) {
changes.added.push({ path, handle: newFile.handle });
} else if (oldFile.lastModified !== newFile.lastModified || oldFile.size !== newFile.size) {
changes.modified.push({ path, handle: newFile.handle });
}
});
// Provjera izbrisanih datoteka
oldSnapshot.forEach((oldFile, path) => {
if (!newSnapshot.has(path)) {
changes.deleted.push({ path });
}
});
return changes;
}
Korak 3: Enkapsulacija logike u klasu DirectoryWatcher
Konačno, sve omotamo u čistu, ponovno iskoristivu klasu koja upravlja stanjem i intervalom prozivanja, te pruža jednostavan API temeljen на povratnim pozivima (callback).
class DirectoryWatcher {
constructor(directoryHandle, interval = 1000) {
this.directoryHandle = directoryHandle;
this.interval = interval;
this.lastSnapshot = new Map();
this.intervalId = null;
this.onChange = () => {}; // Zadani prazni povratni poziv
}
async check() {
try {
const newSnapshot = await createSnapshot(this.directoryHandle);
const changes = compareSnapshots(this.lastSnapshot, newSnapshot);
if (changes.added.length > 0 || changes.modified.length > 0 || changes.deleted.length > 0) {
this.onChange(changes);
}
this.lastSnapshot = newSnapshot;
} catch (error) {
console.error("Greška prilikom provjere promjena datoteka:", error);
// Potencijalno zaustaviti nadzor ako direktorij više nije dostupan
this.stop();
}
}
async start(callback) {
if (this.intervalId) {
console.log("Nadzornik je već pokrenut.");
return;
}
this.onChange = callback;
// Odmah izvršiti početnu provjeru
this.lastSnapshot = await createSnapshot(this.directoryHandle);
this.intervalId = setInterval(() => this.check(), this.interval);
console.log(`Započet nadzor direktorija "${this.directoryHandle.name}" za promjene.`);
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
console.log(`Zaustavljen nadzor direktorija "${this.directoryHandle.name}".`);
}
}
}
// Kako koristiti klasu DirectoryWatcher
const startButton = document.getElementById('startButton');
const stopButton = document.getElementById('stopButton');
let watcher;
startButton.addEventListener('click', async () => {
try {
const directoryHandle = await window.showDirectoryPicker();
watcher = new DirectoryWatcher(directoryHandle, 2000); // Provjera svake 2 sekunde
watcher.start((changes) => {
console.log("Otkrivene promjene:", changes);
// Sada možete ažurirati svoje korisničko sučelje na temelju ovih promjena
});
} catch (error) {
console.error("Korisnik je otkazao dijalog ili se dogodila greška.", error);
}
});
stopButton.addEventListener('click', () => {
if (watcher) {
watcher.stop();
}
});
Praktični slučajevi upotrebe i globalni primjeri
Ova tehnologija nije samo teorijska vježba; ona omogućuje moćne, stvarne aplikacije dostupne globalnoj publici.
1. Web-IDE-ovi i uređivači koda
Ovo je suštinski slučaj upotrebe. Alati poput VS Code for the Web ili GitHub Codespaces mogu omogućiti razvojnom programeru da otvori lokalnu mapu projekta. Nadzornik direktorija tada može pratiti promjene:
- Sinkronizacija stabla datoteka: Kada se datoteka stvori, izbriše ili preimenuje na disku (možda koristeći drugu aplikaciju), stablo datoteka uređivača se odmah ažurira.
- Osvježavanje uživo/Pregled: Za web razvoj, promjene spremljene u HTML, CSS ili JavaScript datoteke mogu automatski pokrenuti osvježavanje okna za pregled unutar uređivača.
- Pozadinski zadaci: Izmjena datoteke mogla bi pokrenuti pozadinsko linting, provjeru tipova ili kompilaciju.
2. Upravljanje digitalnom imovinom (DAM) za kreativne profesionalce
Fotograf bilo gdje u svijetu spoji svoj fotoaparat na računalo, a fotografije se spremaju u određenu "Dolaznu" mapu. Web-alat za upravljanje fotografijama, nakon što mu je odobren pristup ovoj mapi, može je nadzirati za nove dodatke. Čim se pojavi nova JPEG ili RAW datoteka, web aplikacija je može automatski uvesti, generirati minijaturu i dodati je u korisničku knjižnicu bez ikakve ručne intervencije.
3. Znanstveni i alati za analizu podataka
Oprema istraživačkog laboratorija mogla bi generirati stotine malih CSV ili JSON datoteka s podacima po satu u određeni izlazni direktorij. Web-nadzorna ploča može pratiti ovaj direktorij. Kako se dodaju nove podatkovne datoteke, može ih parsirati i ažurirati grafikone, dijagrame i statističke sažetke u stvarnom vremenu, pružajući trenutne povratne informacije o tekućem eksperimentu. Ovo je globalno primjenjivo u poljima od biologije do financija.
4. Aplikacije za bilježenje i dokumentaciju koje rade lokalno (Local-First)
Mnogi korisnici preferiraju čuvanje svojih bilješki kao običnih tekstualnih ili Markdown datoteka u lokalnoj mapi, što im omogućuje korištenje moćnih desktop uređivača poput Obsidiana ili Typore. Progresivna web aplikacija (PWA) mogla bi djelovati kao pratitelj, nadzirući ovu mapu. Kada korisnik uredi datoteku i spremi je, web aplikacija otkriva izmjenu i ažurira vlastiti prikaz. To stvara besprijekorno, sinkronizirano iskustvo između izvornih i web alata, poštujući korisnikovo vlasništvo nad njihovim podacima.
Izazovi, ograničenja i najbolje prakse
Iako je nevjerojatno moćna, implementacija nadzora direktorija dolazi s nizom izazova i odgovornosti.
Kompatibilnost preglednika
File System Access API je moderna tehnologija. Krajem 2023. godine, primarno je podržan u preglednicima temeljenim na Chromiumu kao što su Google Chrome, Microsoft Edge i Opera. Nije dostupan u Firefoxu ili Safariju. Stoga je ključno:
- Detekcija značajki: Uvijek provjerite postojanje 'showDirectoryPicker' in window prije pokušaja korištenja API-ja.
- Pružanje alternativa (fallbacks): Ako API nije podržan, elegantno degradirajte iskustvo. Možete se vratiti na tradicionalni element <input type="file" multiple>, informirajući korisnika o poboljšanim mogućnostima dostupnim u podržanom pregledniku.
Razmatranja o performansama
Prozivanje (polling) je inherentno manje učinkovito od pristupa temeljenog na događajima na razini sustava. Trošak performansi izravno je povezan s veličinom i dubinom nadziranog direktorija te učestalošću intervala prozivanja.
- Veliki direktoriji: Skeniranje direktorija s desetcima tisuća datoteka svake sekunde može trošiti značajne resurse procesora i isprazniti bateriju na prijenosnom računalu.
- Učestalost prozivanja: Odaberite najduži interval koji je prihvatljiv za vaš slučaj upotrebe. Uređivač koda u stvarnom vremenu možda treba interval od 1-2 sekunde, ali uvoznik foto-knjižnice može biti u redu s intervalom od 10-15 sekundi.
- Optimizacija: Naša usporedba snimki stanja već je optimizirana provjerom samo lastModified i size, što je mnogo brže od heširanja sadržaja datoteka. Izbjegavajte čitanje sadržaja datoteka unutar petlje prozivanja osim ako je to apsolutno nužno.
- Promjene fokusa: Pametna optimizacija je pauziranje nadzornika kada kartica preglednika nije u fokusu koristeći Page Visibility API.
Sigurnost i povjerenje korisnika
Povjerenje je najvažnije. Korisnici su s pravom oprezni pri davanju pristupa web stranicama njihovim lokalnim datotekama. Kao programer, morate biti odgovoran upravitelj ove moći.
- Budite transparentni: Jasno objasnite u svom korisničkom sučelju zašto trebate pristup direktoriju. Poruka poput "Odaberite mapu projekta kako biste omogućili sinkronizaciju datoteka uživo" puno je bolja od generičkog gumba "Otvori mapu".
- Zatražite pristup na korisničku akciju: Nikada nemojte pokretati upit showDirectoryPicker() bez izravne i očite korisničke akcije, kao što je klik na gumb.
- Elegantno rukujte odbijanjima: Ako korisnik klikne "Odustani" ili odbije zahtjev za dopuštenje, vaša aplikacija bi trebala elegantno obraditi to stanje bez da se pokvari.
Najbolje prakse za UI/UX
Dobro korisničko iskustvo ključno je da bi se ova moćna značajka osjećala intuitivno i sigurno.
- Pružite jasne povratne informacije: Uvijek prikažite naziv direktorija koji se trenutno nadzire. To podsjeća korisnika koji je pristup odobren.
- Ponudite eksplicitne kontrole: Uključite jasne gumbe "Pokreni nadzor" i "Zaustavi nadzor". Korisnik bi se uvijek trebao osjećati kao da ima kontrolu nad procesom.
- Rukujte greškama: Što se događa ako korisnik preimenuje ili izbriše nadzirani direktorij dok vaša aplikacija radi? Vaše sljedeće prozivanje vjerojatno će izbaciti grešku. Uhvatite te greške i obavijestite korisnika, možda zaustavljanjem nadzornika i traženjem da odabere novi direktorij.
Budućnost: Što slijedi za pristup datotečnom sustavu na webu?
Trenutni pristup temeljen na prozivanju je pametno i učinkovito rješenje, ali nije idealno dugoročno rješenje. Zajednica za web standarde je toga svjesna.
Najočekivaniji budući razvoj je potencijalno dodavanje izvornog, događajima vođenog mehanizma za nadzor datotečnog sustava API-ju. To bi bila prava prekretnica, omogućujući preglednicima da se povežu s vlastitim učinkovitim sustavima obavijesti operativnog sustava (poput inotify na Linuxu, FSEvents na macOS-u ili ReadDirectoryChangesW na Windowsima). To bi eliminiralo potrebu za prozivanjem, drastično poboljšavajući performanse i učinkovitost, posebno za velike direktorije i na uređajima s baterijskim napajanjem.
Iako ne postoji čvrst vremenski okvir za takvu značajku, njezin potencijal je jasan pokazatelj smjera u kojem se web platforma kreće: prema budućnosti u kojoj mogućnosti web aplikacija nisu ograničene izoliranim okruženjem preglednika, već samo našom maštom.
Zaključak
Nadzor direktorija datotečnog sustava na frontendu, pogonjen File System Access API-jem, je transformativna tehnologija. Ona ruši dugogodišnju barijeru između weba i lokalnog desktop okruženja, omogućujući novu generaciju sofisticiranih, interaktivnih i produktivnih aplikacija temeljenih na pregledniku. Razumijevanjem temeljnog API-ja, implementacijom robusne strategije prozivanja i pridržavanjem najboljih praksi za performanse i povjerenje korisnika, programeri mogu graditi iskustva koja se čine integriranijima i moćnijima nego ikad prije.
Iako se trenutno oslanjamo na izgradnju vlastitih nadzornika, principi o kojima smo raspravljali su temeljni. Kako se web platforma nastavlja razvijati, sposobnost besprijekorne i učinkovite interakcije s lokalnim podacima korisnika ostat će kamen temeljac modernog razvoja aplikacija, osnažujući programere da grade uistinu globalne alate koji su dostupni svakome s preglednikom.